#pragma once
#include <string>
#include <stdio.h>

using namespace std;
using namespace lo;

namespace System {

	typedef lo::object_base	Object;

	// Define the internal decimal type
#ifndef DECIMAL_NEG
#ifndef DECIMAL_SETZERO
	typedef struct tagDEC {
		uint16_t wReserved;
		union {
			struct {
				uint8_t scale;
				uint8_t sign;
			};
			uint16_t signscale;
		};
		uint32_t Hi32;
		union {
			struct {
#ifdef _MAC
				uint32_t Mid32;
				uint32_t Lo32;
#else
				uint32_t Lo32;
				uint32_t Mid32;
#endif
			};
			uint64_t Lo64;
		};
	} DECIMAL;
#define DECIMAL_NEG ((BYTE)0x80)
#define DECIMAL_SETZERO(dec) {(dec).Lo64 = 0; (dec).Hi32 = 0; (dec).signscale = 0;}
#endif // DECIMAL_SETZERO
#endif // DECIMAL_NEG

	union ConsoleKey {
	public:
		ConsoleKey( int init ) : _value(init) {}
		enum { Backspace=8, Tab=9, Clear=12, Enter=13, Pause=19, Escape=27, Spacebar=32, PageUp=33, PageDown=34, End=35, Home=36, LeftArrow=37, UpArrow=38, RightArrow=39
			, DownArrow=40, Select=41, Print=42, Execute=43, PrintScreen=44, Insert=45, Delete=46, Help=47, D0=48, D1=49, D2=50, D3=51, D4=52, D5=53, D6=54, D7=55, D8=56, D9=57
			, A=65, B=66, C=67, D=68, E=69, F=70, G=71, H=72, I=73, J=74, K=75, L=76, M=77, N=78, O=79, P=80, Q=81, R=82, S=83, T=84, U=85, V=86, W=87, X=88, Y=89, Z=90, LeftWindows=91
			, RightWindows=92, Applications=93, Sleep=95, NumPad0=96, NumPad1=97, NumPad2=98, NumPad3=99, NumPad4=100, NumPad5=101, NumPad6=102, NumPad7=103, NumPad8=104, NumPad9=105
			, Multiply=106, Add=107, Separator=108, Subtract=109, Decimal=110, Divide=111, F1=112, F2=113, F3=114, F4=115, F5=116, F6=117, F7=118, F8=119, F9=120, F10=121, F11=122
			, F12=123, F13=124, F14=125, F15=126, F16=127, F17=128, F18=129, F19=130, F20=131, F21=132, F22=133, F23=134, F24=135, BrowserBack=166, BrowserForward=167, BrowserRefresh=168
			, BrowserStop=169, BrowserSearch=170, BrowserFavorites=171, BrowserHome=172, VolumeMute=173, VolumeDown=174, VolumeUp=175, MediaNext=176, MediaPrevious=177, MediaStop=178
			, MediaPlay=179, LaunchMail=180, LaunchMediaSelect=181, LaunchApp1=182, LaunchApp2=183, Oem1=186, OemPlus=187, OemComma=188, OemMinus=189, OemPeriod=190, Oem2=191
			, Oem3=192, Oem4=219, Oem5=220, Oem6=221, Oem7=222, Oem8=223, Oem102=226, Process=229, Packet=231, Attention=246, CrSel=247, ExSel=248, EraseEndOfFile=249, Play=250
			, Zoom=251, NoName=252, Pa1=253, OemClear=254 };
		inline operator int() { return _value; }
		inline bool HasFlag( int check) { return (check & _value) != 0; }
	private:
		int _value;
	};

	union ConsoleModifiers {
	public:
		ConsoleModifiers( int init ) : _value(init) {}
		enum { Alt=1, Shift=2, Control=4 };
		inline operator int() { return _value; }
		inline bool HasFlag( int check) { return (check & _value) != 0; }
	private:
		int _value;
	};

	union ConsoleSpecialKey {
	public:
		ConsoleSpecialKey( int init ) : _value(init) {}
		enum { ControlC=0, ControlBreak=1 };
		inline operator int() { return _value; }
		inline bool HasFlag( int check) { return (check & _value) != 0; }
	private:
		int _value;
	};


	union ConsoleColor {
	public:
		ConsoleColor( int init ) : _value(init) {}
		enum { Black=0, DarkBlue=1, DarkGreen=2, DarkCyan=3, DarkRed=4, DarkMagenta=5, DarkYellow=6, Gray=7,
			DarkGray=8, Blue=9, Green=10, Cyan=11, Red=12, Magenta=13, Yellow=14, White=15 };
		inline operator int() { return _value; }
		inline bool HasFlag( int check) { return (check & _value) != 0; }
	private:
		int _value;
	};

	union _ConsoleKeyInfo
	{
		struct { int _keyChar : 16;	int	_key : 8;	int	_mods : 4; };
		int	_value;
	};

	bool operator==(const _ConsoleKeyInfo &obj1,const _ConsoleKeyInfo &obj2);

	struct ConsoleKeyInfo : object_base {
	public:
		ConsoleKeyInfo(const _ConsoleKeyInfo value ) : m_value(value) {}
		ConsoleKeyInfo(wchar_t keyChar, ConsoleKey key, bool shift, bool alt, bool control);
		_declspec(property(get=get_KeyChar))		wchar_t 								KeyChar;	inline wchar_t		get_KeyChar()	{ return m_value._keyChar; }
		_declspec(property(get=get_Key))			ConsoleKey 								Key;		ConsoleKey			get_Key()		{ return ConsoleKey(m_value._key);}
		_declspec(property(get=get_Modifiers))		ConsoleModifiers 						Modifiers;	ConsoleModifiers	get_Modifiers()	{ return ConsoleModifiers(m_value._mods); }
		int											CompareTo(const ConsoleKeyInfo &value) const;
		_ConsoleKeyInfo	m_value;
	};

	class EventArgs : public Object {	// System
		EventArgs();
		static ref<EventArgs>		Empty;
	};

	class ConsoleCancelEventArgs : public EventArgs {
	public:
		_declspec(property(get=get_Cancel))		bool 									Cancel;
		_declspec(property(get=get_SpecialKey))	ConsoleSpecialKey 					SpecialKey;
		bool							get_Cancel();
		void							set_Cancel(bool value);
		ConsoleSpecialKey				get_SpecialKey();
	private:
		ConsoleCancelEventArgs(ConsoleSpecialKey &type);
		int								m_type;
		bool							m_cancel;
	};

	class ConsoleCancelEventHandler /* : public MulticastDelegate */ {
	public:
		ConsoleCancelEventHandler(const Object &object, intptr_t method);
		virtual void					Invoke(const Object &sender, const ConsoleCancelEventArgs &e);
//		virtual lo::iref<IAsyncResult>		BeginInvoke(const Object &sender, const ConsoleCancelEventArgs &e, const lo::ref<AsyncCallback> &callback, const Object &object);
//		virtual void					EndInvoke(const lo::iref<IAsyncResult> &result);
	};


	class Console {
	public:
		//		static struct { inline operator Ref<System::IO::TextWriter>() { return get_Error(); } } Error;
		//		static struct { inline operator Ref<System::IO::TextReader>() { return get_In(); } } In;
		//		static struct { inline operator Ref<System::IO::TextWriter>() { return get_Out(); } } Out;
		//		static struct { inline operator Ref<System::Text::Encoding>() { return get_InputEncoding(); } } InputEncoding;
		//		static struct { inline operator Ref<System::Text::Encoding>() { return get_OutputEncoding(); } } OutputEncoding;
		static struct { inline operator ConsoleColor() { return get_BackgroundColor(); } } BackgroundColor;
		static struct { inline operator ConsoleColor() { return get_ForegroundColor(); } } ForegroundColor;
		static struct { inline operator int() { return get_BufferHeight(); } } BufferHeight;
		static struct { inline operator int() { return get_BufferWidth(); } } BufferWidth;
		static struct { inline operator int() { return get_WindowHeight(); } } WindowHeight;
		static struct { inline operator int() { return get_WindowWidth(); } } WindowWidth;
		static struct { inline operator int() { return get_LargestWindowWidth(); } } LargestWindowWidth;
		static struct { inline operator int() { return get_LargestWindowHeight(); } } LargestWindowHeight;
		static struct { inline operator int() { return get_WindowLeft(); } } WindowLeft;
		static struct { inline operator int() { return get_WindowTop(); } } WindowTop;
		static struct { inline operator int() { return get_CursorLeft(); } } CursorLeft;
		static struct { inline operator int() { return get_CursorTop(); } } CursorTop;
		static struct { inline operator int() { return get_CursorSize(); } } CursorSize;
		static struct { inline operator bool() { return get_CursorVisible(); } } CursorVisible;
		static struct { inline operator std::string() { return get_Title(); } } Title;
		static struct { inline operator bool() { return get_KeyAvailable(); } } KeyAvailable;
		static struct { inline operator bool() { return get_NumberLock(); } } NumberLock;
		static struct { inline operator bool() { return get_CapsLock(); } } CapsLock;
		static struct { inline operator bool() { return get_TreatControlCAsInput(); } } TreatControlCAsInput;
		//		static Ref<System::IO::TextWriter>	get_Error();
		//		static Ref<System::IO::TextReader>	get_In();
		//		static Ref<System::IO::TextWriter>	get_Out();
		//		static Ref<System::Text::Encoding>	get_InputEncoding();
		//		static void					set_InputEncoding(const System::Text::Encoding &value);
		//		static Ref<System::Text::Encoding>	get_OutputEncoding();
		//		static void					set_OutputEncoding(const System::Text::Encoding &value);
		static void					Beep();
		static void					Beep(int frequency, int duration);
		static void					Clear();
		static ConsoleColor			get_BackgroundColor();
		static void					set_BackgroundColor(ConsoleColor value);
		static ConsoleColor			get_ForegroundColor();
		static void					set_ForegroundColor(ConsoleColor value);
		static void					ResetColor();
		static void					MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop);
		static void					MoveBufferArea(int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop, wchar_t sourceChar, ConsoleColor &sourceForeColor, ConsoleColor &sourceBackColor);
		static int					get_BufferHeight();
		static void					set_BufferHeight(int value);
		static int					get_BufferWidth();
		static void					set_BufferWidth(int value);
		static void					SetBufferSize(int width, int height);
		static int					get_WindowHeight();
		static void					set_WindowHeight(int value);
		static int					get_WindowWidth();
		static void					set_WindowWidth(int value);
		static void					SetWindowSize(int width, int height);
		static int					get_LargestWindowWidth();
		static int					get_LargestWindowHeight();
		static int					get_WindowLeft();
		static void					set_WindowLeft(int value);
		static int					get_WindowTop();
		static void					set_WindowTop(int value);
		static void					SetWindowPosition(int left, int top);
		static int					get_CursorLeft();
		static void					set_CursorLeft(int value);
		static int					get_CursorTop();
		static void					set_CursorTop(int value);
		static void					SetCursorPosition(int left, int top);
		static int					get_CursorSize();
		static void					set_CursorSize(int value);
		static bool					get_CursorVisible();
		static void					set_CursorVisible(bool value);
		static string				get_Title();
		static void					set_Title(const char *value);
		static ConsoleKeyInfo		ReadKey();
		static ConsoleKeyInfo		ReadKey(bool intercept);
		static bool					get_KeyAvailable();
		static bool					get_NumberLock();
		static bool					get_CapsLock();
		static bool					get_TreatControlCAsInput();
		static void					set_TreatControlCAsInput(bool value);
		static void					add_CancelKeyPress(const ref<ConsoleCancelEventHandler> &value);
		static void					remove_CancelKeyPress(const ref<ConsoleCancelEventHandler> &value);
		// 		static Ref<System::IO::Stream>	OpenStandardError();
		// 		static Ref<System::IO::Stream>	OpenStandardError(int bufferSize);
		// 		static Ref<System::IO::Stream>	OpenStandardInput();
		// 		static Ref<System::IO::Stream>	OpenStandardInput(int bufferSize);
		// 		static Ref<System::IO::Stream>	OpenStandardOutput();
		// 		static Ref<System::IO::Stream>	OpenStandardOutput(int bufferSize);
		//static void					SetIn(const System::IO::TextReader &newIn);
		//static void					SetOut(const System::IO::TextWriter &newOut);
		//static void					SetError(const System::IO::TextWriter &newError);
		static int					Read();
		static std::string			ReadLine();
		static void					WriteLine();
		static void					WriteLine(bool value);
		static void					WriteLine(wchar_t value);
		static void					WriteLine(const vector<wchar_t> &buffer);
		static void					WriteLine(const vector<wchar_t> &buffer, int index, int count);
		static void					WriteLine(DECIMAL value);
		static void					WriteLine(double value);
		static void					WriteLine(float value);
		static void					WriteLine(int value);
		static void					WriteLine(unsigned int value);
		static void					WriteLine(__int64 value);
		static void					WriteLine(unsigned __int64 value);
		static void					WriteLine(const Object &value);
		inline static void			WriteLine(const char *value)	{ puts(value); }
		static void					WriteLine(const char *format, const Object &arg0);
		static void					WriteLine(const char *format, const Object &arg0, const Object &arg1);
		static void					WriteLine(const char *format, const Object &arg0, const Object &arg1, const Object &arg2);
		static void					WriteLine(const char *format, const Object &arg0, const Object &arg1, const Object &arg2, const Object &arg3);
		static void					WriteLine(const char *format, const vector<lo::object> &arg);
		static void					Write(const char *format, const Object &arg0);
		static void					Write(const char *format, const Object &arg0, const Object &arg1);
		static void					Write(const char *format, const Object &arg0, const Object &arg1, const Object &arg2);
		static void					Write(const char *format, const Object &arg0, const Object &arg1, const Object &arg2, const Object &arg3);
		static void					Write(const char *format, const vector<lo::object> &arg);
		static void					Write(bool value);
		static void					Write(wchar_t value);
		static void					Write(const vector<wchar_t> &buffer);
		static void					Write(const vector<wchar_t> &buffer, int index, int count);
		static void					Write(double value);
		static void					Write(DECIMAL value);
		static void					Write(float value);
		static void					Write(int value);
		static void					Write(unsigned int value);
		static void					Write(__int64 value);
		static void					Write(unsigned __int64 value);
		static void					Write(const Object &value);
		static void					Write(const char *value);
	private:
		class ControlCDelegateData : public Object {
		private:
			ControlCDelegateData(ConsoleSpecialKey &controlKey, const lo::ref<ConsoleCancelEventHandler> &cancelCallbacks);
			int							ControlKey;
			bool							Cancel;
			bool							DelegateStarted;
			//			Ref<System::Threading::ManualResetEvent> CompletionEvent;
			lo::ref<ConsoleCancelEventHandler> CancelCallbacks;
		};

		static struct { inline operator lo::object() { return get_InternalSyncObject(); } } InternalSyncObject;
		static struct { inline operator intptr_t() { return get_ConsoleInputHandle(); } } ConsoleInputHandle;
		static struct { inline operator intptr_t() { return get_ConsoleOutputHandle(); } } ConsoleOutputHandle;
		static lo::object			get_InternalSyncObject();
		static intptr_t				get_ConsoleInputHandle();
		static intptr_t				get_ConsoleOutputHandle();
		//static void					InitializeStdOutError(bool stdout);
		//static Ref<System::IO::Stream>	GetStandardFile(int stdHandleName, System::IO::FileAccess &access, int bufferSize);
		//static Ref<Microsoft::Win32::Color>	ConsoleColorToColorAttribute(ConsoleColor &color, bool isBackground);
		//static Ref<ConsoleColor>		ColorAttributeToConsoleColor(Microsoft::Win32::Color &c);
		//static lo::ref<CONSOLE_SCREEN_BUFFER_INFO>	GetBufferInfo();
		//static lo::ref<CONSOLE_SCREEN_BUFFER_INFO>	GetBufferInfo(bool throwOnNoConsole, bool & succeeded);
		//static bool					IsAltKeyDown(const Microsoft::Win32::InputRecord &ir);
		//static bool					IsKeyDownEvent(const Microsoft::Win32::InputRecord &ir);
		//static bool					IsModKey(const Microsoft::Win32::InputRecord &ir);
		static bool					BreakEvent(int controlType);
		static void					ControlCDelegate(const Object &data);
		//		static bool					ConsoleHandleIsValid(const ref<Microsoft::Win32::SafeHandles::SafeFileHandle> &handle);
		//		static Ref<System::IO::TextReader> _in;
		//		static Ref<System::IO::TextWriter> _out;
		//		static Ref<System::IO::TextWriter> _error;
		static ref<ConsoleCancelEventHandler> _cancelCallbacks;
		//		static ControlCHooker			_hooker;
		//		static Microsoft::Win32::InputRecord _cachedInputRecord;
		static bool					_haveReadDefaultColors;
		static unsigned char			_defaultColors;
		static bool					_wasOutRedirected;
		static bool					_wasErrorRedirected;
		//		static Ref<System::Text::Encoding> _inputEncoding;
		//		static Ref<System::Text::Encoding> _outputEncoding;
		static lo::object				s_InternalSyncObject;
		static intptr_t					_consoleInputHandle;
		static intptr_t					_consoleOutputHandle;
		static const int				_DefaultConsoleBufferSize = 256;
		static const short				AltVKCode = 18;
		static const int				NumberLockVKCode = 144;
		static const int				CapsLockVKCode = 20;
		static const int				MinBeepFrequency = 37;
		static const int				MaxBeepFrequency = 32767;
		static const int				MaxConsoleTitleLength = 24500;
	};

#define CLASSPROP(name,type)	__declspec( property( get=get_##name, put=put_##name ) ) type name;

	class DateTime
	{
	public:
		DateTime();
		DateTime(time_t & t);

		static const long long	FILETIMEUNIXBASE = 0x019db1ded53e8000;		// Number of FILETIME units at Jan 1, 1970 midnight
		static const long SEC_TO_100NANOSEC = 10000000;					// Conversion from seconds to 0.1 microsecond conversion

		CLASSPROP(Hour,int);
		CLASSPROP(Minute,int);
		CLASSPROP(Second,int);
		CLASSPROP(Month,int);
		CLASSPROP(Day,int);
		CLASSPROP(Year,int);
		
		/** Converts a string with an acceptable time format string into a DateTime form. */
		static	bool	TryParse(const char *format, DateTime& time );
		/** Returns the unix time for the given file time. 0 = could be underflow, 4294967295 = could be overflow. */
		static	DWORD	FileTimeToUnixTime(const FILETIME & fileTime) throw();
		/** Returns a time stamp from a SYSTEMTIME structure in the form of ddd, dd-MMM-yyyy HH':'mm':'ss GMT. */
		static	string	SystemTimeStamp( const SYSTEMTIME & lpSystemTime );
		/** Returns a time stamp from a unix time in the form of ddd, dd-MMM-yyyy HH':'mm':'ss GMT. */
		static	string	UnixTimeStamp( DWORD dwUnixTime );
		/** Converts a SYSTEMTIME structure to UNIX time */
		static	DWORD	SystemTimeToUnix( const SYSTEMTIME & lpSystemTime );
		/** Converts a UNIXTIME to SYSTEMTIME */
		static	bool	UnixTimeToSys( DWORD dwUnixTime, SYSTEMTIME & lpSystemTime );
		operator time_t () const	{ return m_time; }
	private:
		time_t	m_time;
	};

	class Guid
	{
	public:
		static Guid NewGuid();
		string ToString();
	private:
		GUID	m_guid;
	};

	class Uri : public lo::object
	{
	public:
		Uri(const char *uri) : m_uri(uri) {}
		Uri(const Uri &uri,const char *additionalPath);
		Uri(const Uri &absoluteUri, Uri &relativeUri);
		static void EscapeAsciiChar(char ch, char to[], int & pos);
		static int FromHex( char digit );
		std::string	get_AbsolutePath() const;
		bool		get_IsFile();
		static bool IsHexDigit(char character);
		static const char *HexUpperChars;
		static const char *SchemeDelimiter;
		static const char *UriSchemeFile;
		static const char *UriSchemeFtp;
		static const char *UriSchemeGopher;
		static const char *UriSchemeHttp;
		static const char *UriSchemeHttps;
		static const char *UriSchemeMailto;
		static const char *UriSchemeNetPipe;
		static const char *UriSchemeNetTcp;
		static const char *UriSchemeNews;
		static const char *UriSchemeNntp;
	private:
		std::string m_uri;
	};

	class Environment
	{
	public:
		union SpecialFolder {
			SpecialFolder(int value) : m_value(value) {}
			enum { Desktop = 0, Programs = 2, Personal = 5, MyDocuments = 5, Favorites = 6, Startup = 7, Recent = 8, SendTo = 9, StartMenu = 11, MyMusic = 13, MyVideos = 14,
				DesktopDirectory = 16, MyComputer = 17, NetworkShortcuts = 19, Fonts = 20, Templates = 21, CommonStartMenu = 22, CommonPrograms = 23, CommonStartup = 24, CommonDesktopDirectory = 25,
				ApplicationData = 26, PrinterShortcuts = 27, LocalApplicationData = 28,	InternetCache = 32, Cookies = 33, History = 34,	CommonApplicationData = 35,	Windows = 36, System = 37,
				ProgramFiles = 38, MyPictures = 39,	UserProfile = 40, SystemX86 = 41, ProgramFilesX86 = 42,	CommonProgramFiles = 43, CommonProgramFilesX86 = 44, CommonTemplates = 45,
				CommonDocuments = 46, CommonAdminTools = 47, AdminTools = 48, CommonMusic = 53, CommonPictures = 54, CommonVideos = 55,	Resources = 56,	LocalizedResources = 57, CommonOemLinks = 58,
				CDBurning = 59 };
			operator int() { return m_value; }
		private:
			int m_value;
		};

		union SpecialFolderOption {
			SpecialFolderOption( int value ) : m_value(value) {}
			enum { None = 0, DoNotVerify = 16384, Create = 32768 };
			operator int() { return m_value; }
		private:
			int m_value;
		};

		static string get_CommandLine();
		static string GetFolderPath(SpecialFolder specialFolder);
	};

	class Math
	{
	public:
		static LONG			hypotenuse(LONG x, LONG y);
		static LONG			sqrt(LONG x);
	};

};

using namespace System;
